﻿using System;
using System.ComponentModel;
using System.Data.EntityClient;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Windows;
using System.Windows.Input;
using System.Xml.Linq;
using Analyzer;
using Analyzer.ViewModel;
using Model;

namespace Presenter.ViewModel
{
    internal class MainWindowViewModel : ViewModelBase
    {
        #region Lifecycle

        public MainWindowViewModel()
        {
            this.DoStartJTreeMap = Properties.Settings.Default.StartJTreeMap;
        }

        #endregion Lifecycle

        #region Properties

        private ActualEntities pContext;
        public ActualEntities Context
        {
            get { return pContext; }
            private set
            {
                if (value != pContext)
                {
                    pContext = value;
                    OnPropertyChanged("Context");
                }
            }
        }

        private string pFileName;
        public string FileName
        {
            get { return pFileName; }
            private set
            {
                if (value.Equals(pFileName) == false)
                {
                    pFileName = value;
                    OnPropertyChanged("FileName");
                }
            }
        }

        private string pJavaDir;
        private string JavaDir
        {
            get
            {
                if (pJavaDir == null)
                {
                    String path = Environment.GetEnvironmentVariable("path");
                    String[] folders = path.Split(';');
                    foreach (String folder in folders)
                    {
                        if (File.Exists(folder + "java.exe"))
                        {
                            pJavaDir = folder;
                            break;
                        }
                        else if (File.Exists(folder + "\\java.exe"))
                        {
                            pJavaDir = folder + "\\";
                            break;
                        }
                    }
                }
                return pJavaDir;
            }
            set
            {
                if (pJavaDir != value)
                    pJavaDir = value;
            }
        }

        private bool HasError { get; set; }

        #region Presentation

        private bool pDoStartJTreeMap;
        public bool DoStartJTreeMap
        {
            get
            {
                return pDoStartJTreeMap;
            }
            set
            {
                if (value != pDoStartJTreeMap)
                {
                    pDoStartJTreeMap = value;
                    OnPropertyChanged("DoStartJTreeMap");
                    Properties.Settings.Default.StartJTreeMap = pDoStartJTreeMap;
                }
            }
        }

        #endregion Presentation

        #endregion Properties

        #region Commands

        #region BrowseReportCommand

        private RelayCommand pBrowseReportCommand;
        public ICommand BrowseReportCommand
        {
            get
            {
                if (pBrowseReportCommand == null)
                    pBrowseReportCommand =
                        new RelayCommand(
                            param =>
                            {
                                this.HasError = false;
                                Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
                                ofd.AddExtension = true;
                                ofd.DefaultExt = ".db3";
                                ofd.Filter = "Adatbázis|*.db3";
                                ofd.FilterIndex = 0;
                                ofd.Title = "Riport tallózása";
                                ofd.ValidateNames = true;
                                ofd.Multiselect = false;
                                ofd.CheckFileExists = true;
                                ofd.CheckPathExists = true;
                                bool? success = ofd.ShowDialog();
                                if (success.HasValue && success.Value == true)
                                {
                                    new BrowseReportCommandAide(LoadDB).BeginInvoke(
                                        ofd.FileName,
                                        new AsyncCallback(BrowseReportCommandAide_CallbackMethod),
                                        null);
                                }
                            }
                        );
                return pBrowseReportCommand;
            }
        }

        delegate void BrowseReportCommandAide(string fileName);

        private void LoadDB(string fileName)
        {
            EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();
            builder.Metadata = "res://*/ActualModel.csdl|res://*/ActualModel.ssdl|res://*/ActualModel.msl";
            builder.Provider = "System.Data.SQLite";
            builder.ProviderConnectionString = "data source=\"" + fileName + "\"";
            this.Context = new ActualEntities(builder.ConnectionString);
            this.FileName = fileName;
            if (this.Context.QualityProfileItems.Count() == 0)
                MessageBox.Show("Nincs minőségi profil rögzítve!", "", MessageBoxButton.OK,
                    MessageBoxImage.Exclamation);
            else
            {
                GenerateInputForJTreeMap();
                if (this.DoStartJTreeMap == true)
                    StartJTreeMap(this.JavaDir);
                else
                    MessageBox.Show("Kész!");
            }
        }

        private void BrowseReportCommandAide_CallbackMethod(IAsyncResult result)
        {
            BrowseReportCommandAide caller =
                (BrowseReportCommandAide)((AsyncResult)result).AsyncDelegate;
            caller.EndInvoke(result);
        }

        #endregion BrowseReportCommand

        private RelayCommand pBrowseJavaCommand;
        public ICommand BrowseJavaCommand
        {
            get
            {
                if (pBrowseJavaCommand == null)
                    pBrowseJavaCommand =
                        new RelayCommand(
                            param =>
                            {
                                Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
                                ofd.AddExtension = true;
                                //ofd.DefaultExt = ".exe";
                                //ofd.Filter = "Végrehajtható|*.exe";
                                ofd.FilterIndex = 0;
                                ofd.Title = "Java.exe tallózása";
                                ofd.ValidateNames = true;
                                ofd.Multiselect = false;
                                ofd.CheckFileExists = true;
                                ofd.CheckPathExists = true;
                                ofd.InitialDirectory =
                                    Environment.GetFolderPath(Environment.SpecialFolder.MyComputer);
                                bool? success = ofd.ShowDialog();
                                if (success.HasValue && success.Value == true)
                                    this.JavaDir = ofd.FileName;
                                else
                                    this.HasError = true;
                            },
                            param => true);
                return pBrowseJavaCommand;
            }
        }

        #endregion Commands

        #region Methods

        private void GenerateInputForJTreeMap()
        {
            XElement root = new XElement("root");
            root.Add(new XElement("label", "Quality profile"));
            foreach (var qchar in this.Context.QualityCharacteristics)
            {
                XElement branch = new XElement("branch");
                branch.Add(new XElement("label", qchar.Name));
                foreach (var qsubchar in qchar.Category_Subcharacteristic)
                {
                    double weight = 0.0;
                    double value = -GetValue(qsubchar);
                    var query = this.Context.QualityProfileItems.Where(
                            qpi => qpi.CategoryName.Equals(qsubchar.Name));
                    if (query.Count() > 0)
                        weight = query.First().Weight;
                    branch.Add(new XElement("leaf",
                        new XElement("label", qsubchar.Name),
                        new XElement("weight", weight),
                        new XElement("value", value)));
                }
                root.Add(branch);
            }
            string appDataPath =
                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\Analyzer";
            if (Directory.Exists(appDataPath) == false)
                Directory.CreateDirectory(appDataPath);
            string path =
                appDataPath + "\\"
                + this.FileName.Split(new string[] { "\\" }, StringSplitOptions.None).Last()
                + "_JTMinput.xml";
            root.Save(path);
        }

        private double GetValue(Category_Subcharacteristic subcharacteristic)
        {
            double numberOfRulesToSubchar = subcharacteristic.Category.Mappings.Count;
            double numberOfRules = this.Context.Rules.Count();
            double numberOfRelevantMessages = 0.0;
            foreach (var message in this.Context.Messages)
            {
                if (message.GetSubcharacteristics().Contains(subcharacteristic))
                    numberOfRelevantMessages++;
            }
            if (numberOfRules > 0)
                return numberOfRelevantMessages * (numberOfRulesToSubchar / numberOfRules);
            else
                return 0.0;
        }

        private bool StartJTreeMap(string javaDir)
        {
            bool success = false;
            using (Process p = new Process())
            {
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = false;
                if (javaDir == null)
                {
                    if (Properties.Settings.Default.JavaLocalPath != null
                        && File.Exists(Properties.Settings.Default.JavaLocalPath) == true)
                    {
                        success = StartJTreeMap(Properties.Settings.Default.JavaLocalPath);
                        MessageBox.Show("java.exe not found!");
                    }
                    this.BrowseJavaCommand.Execute(null);
                    if (this.HasError == false)
                    {
                        success = StartJTreeMap(this.JavaDir);
                        Properties.Settings.Default.JavaLocalPath = this.JavaDir;
                    }
                    else
                        return false;
                }
                if (success == false)
                {
                    p.StartInfo.FileName =
                        this.JavaDir.EndsWith("java.exe") == true
                        ? this.JavaDir
                        : this.JavaDir + "java.exe";

                    p.StartInfo.Arguments = "-jar ..\\..\\3rdparty\\jtreemap-site-1.1.0\\jtreemap-1.1.0.jar";

                    try
                    {
                        p.Start();
                        StreamReader reader = p.StandardOutput;
                        StreamWriter writer = p.StandardInput;
                        StreamReader errorReader = p.StandardError;
                        writer.AutoFlush = true;
                        String rawOutput = reader.ReadToEnd();
                        string[] output =
                            rawOutput.Split(new string[] { Environment.NewLine },
                                StringSplitOptions.RemoveEmptyEntries);
                        //DispatchService.Dispatch(() =>
                        //{
                        //    foreach (var item in output)
                        //    {
                        //        this.Output.Add(item);
                        //    }
                        //});
                        string error = errorReader.ReadToEnd();
                        //if (error != null && error.Length != 0)
                        //    throw new AnalysisException(error);
                    }
                    catch (Win32Exception ex)
                    {
                        System.Windows.MessageBox.Show(ex.Message + " " + p.StartInfo.FileName);
                        //this.HasError = true;
                    }
                    success = true;
                }
            }
            return success;
        }

        #endregion Methods
    }
}
